#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "_button.h"
#include "button.h"
#include "_font.h"

#ifdef __DEBUG__
#define __E(fmt, args...) fprintf(stderr, "BUTTON ERROR [%d]: " fmt, __LINE__, ## args)
#define __W(fmt, args...) fprintf(stderr, "BUTTON WARNING [%d]: " fmt, __LINE__, ## args)
#else
#define __E(fmt, args...)
#define __W(fmt, args...)
#endif

#define false               0
#define true                1

static button botoes[MAX_NUMBER_BUTTONS];
static int btnId = 0;

int button_create(unsigned int x, unsigned int y, unsigned int height,
        unsigned int width, unsigned int r, unsigned int g, unsigned int b,
        unsigned char *text, unsigned int font_height, unsigned int font_r,
        unsigned int font_g, unsigned int font_b) {

    if (btnId > MAX_NUMBER_BUTTONS) {
        __E("Nao e possivel criar mais botoes. Numero maximo.\n");
        return BUTTON_FAILURE;
    } else {
        botoes[btnId].x = x;
        botoes[btnId].y = y;
        botoes[btnId].h = height;
        botoes[btnId].w = width;
        botoes[btnId].bg_r = r;
        botoes[btnId].bg_g = g;
        botoes[btnId].bg_b = b;
        botoes[btnId].font_r = font_r;
        botoes[btnId].font_g = font_g;
        botoes[btnId].font_b = font_b;
        botoes[btnId].border = DEFAULT_BUTTON_BORDER;
        botoes[btnId].selected = false;
        botoes[btnId].visible = true;
        botoes[btnId].initialized = false;
        botoes[btnId].id = btnId;
        botoes[btnId].font_height = font_height;
        strcpy(botoes[btnId].text, text);
        botoes[btnId].winp = NULL;
        botoes[btnId].previous = &botoes[btnId];
        botoes[btnId].next = &botoes[btnId];
        botoes[btnId].initialized = true;
        return btnId++;
    }
}

signed int button_destroy(signed int buttonId) {
    if (!botoes[buttonId].initialized) {
        __E("Botao nao pode ser destruido: botao nao foi criado.");
        return BUTTON_FAILURE;
    }

    botoes[buttonId].x = 0;
    botoes[buttonId].y = 0;
    botoes[buttonId].h = 0;
    botoes[buttonId].w = 0;
    botoes[buttonId].bg_r = 0;
    botoes[buttonId].bg_g = 0;
    botoes[buttonId].bg_b = 0;
    botoes[buttonId].font_r = 0;
    botoes[buttonId].font_g = 0;
    botoes[buttonId].font_b = 0;
    botoes[buttonId].border = 0;
    botoes[buttonId].font_height = 0;
    botoes[buttonId].redraw = 0;
    botoes[buttonId].blocked = 1;
    botoes[buttonId].selected = 0;
    botoes[buttonId].visible = 0;
    strncpy(botoes[buttonId].text, "", MAX_TEXT_BUTTON);

    button_delFromWindow(buttonId);
    botoes[buttonId].initialized = 0;

    return BUTTON_SUCCESS;
}

/* button_draw desenha um botao no buffer da janela a que ele esta associado */
int button_draw(int buttonId) {
    if (botoes[buttonId].initialized) {
        if (botoes[buttonId].winp) {
            unsigned char pressed_offset;
            if (botoes[buttonId].visible) {
                pressed_offset = botoes[buttonId].selected ? PRESSED_OFFSET : 0;
            } else return BUTTON_SUCCESS;

            unsigned int string_width, string_height, font_x, font_y;
            unsigned int r, g, b;
			int i;

            if (((botoes[buttonId].bg_r + pressed_offset) > 255)
                    || ((botoes[buttonId].bg_g + pressed_offset) > 255)
                    || ((botoes[buttonId].bg_b + pressed_offset) > 255)) {
                r = botoes[buttonId].bg_r - pressed_offset;
                g = botoes[buttonId].bg_g - pressed_offset;
                b = botoes[buttonId].bg_b - pressed_offset;
            } else {
                r = botoes[buttonId].bg_r + pressed_offset;
                g = botoes[buttonId].bg_g + pressed_offset;
                b = botoes[buttonId].bg_b + pressed_offset;
            }

            gfx_render_button(&botoes[buttonId], botoes[buttonId].winp, r, g, b);

			/*
            string_width = font_getStringWidth(botoes[buttonId].text, botoes[buttonId].font_height);
            if (string_width > botoes[buttonId].w) {
                __E("Texto mais largo que o botao!\n");
                return BUTTON_FAILURE;
            }
			*/
			
            string_width = font_getStringWidth(botoes[buttonId].text, botoes[buttonId].font_height);
            if (string_width > botoes[buttonId].w) {
				do {
					i = strlen(botoes[buttonId].text);
					while (botoes[buttonId].text[i] != ' ' && i > 0) i--;
					botoes[buttonId].text[i] = '\0';
					string_width = font_getStringWidth(botoes[buttonId].text, botoes[buttonId].font_height);
				} while (string_width > botoes[buttonId].w);

				/*
				while (string_width > botoes[buttonId].w) {
					i = strlen(botoes[buttonId].text);
					while (botoes[buttonId].text[i] != ' ' && i > 0) i--;
					botoes[buttonId].text[i] = '\0';
					string_width = font_getStringWidth(botoes[buttonId].text, botoes[buttonId].font_height);
				}
				*/
			}
			
            string_height = font_getStringHeight(botoes[buttonId].text, botoes[buttonId].font_height);
            font_x = botoes[buttonId].x + botoes[buttonId].w / 2 - string_width / 2;
            font_y = botoes[buttonId].y + botoes[buttonId].h / 2 + string_height / 2;

            if (font_render(botoes[buttonId].text, font_x, font_y, 0xff, botoes[buttonId].font_height,
                    botoes[buttonId].winp, botoes[buttonId].font_r, botoes[buttonId].font_g,
                    botoes[buttonId].font_b) < 0) {
                __E("Falha na renderizacao da fonte do botao!\n");
                return BUTTON_FAILURE;
            }
        } else {
            __E("Nenhuma tela associada ao botao.\n");
            return BUTTON_FAILURE;
        }
    } else {
        __E("Botao nao foi criado.\n");

        return BUTTON_FAILURE;
    }
}

int button_block(int buttonId) {
    if (botoes[buttonId].initialized) {
        if (botoes[buttonId].winp) {
            botoes[buttonId].blocked = true;
        } else {
            __E("Nenhuma tela associada ao botao.\n");
            return BUTTON_FAILURE;
        }
    } else {
        __E("Botao nao foi criado.\n");

        return BUTTON_FAILURE;
    }
}

int button_unblock(int buttonId) {
    if (botoes[buttonId].initialized) {
        if (botoes[buttonId].winp) {
            botoes[buttonId].blocked = false;
        } else {
            __E("Nenhuma tela associada ao botao.\n");
            return BUTTON_FAILURE;
        }
    } else {
        __E("Botao nao foi criado.\n");

        return BUTTON_FAILURE;
    }
}

/* button_unselect nao atualiza mais o buffer da tela */
int button_unselect(int buttonId) {
    if (botoes[buttonId].initialized) {
        if (botoes[buttonId].winp) {
            botoes[buttonId].selected = false;
            window_set_actualButton_selected(botoes[buttonId].windowId, -1);
            return BUTTON_SUCCESS;
        } else {
            __E("Nenhuma tela associada ao botao.\n");
            return BUTTON_FAILURE;
        }
    } else {
        __E("Botao nao foi criado.\n");

        return BUTTON_FAILURE;
    }
}

/* button_select nao atualiza mais o buffer da tela */
int button_select(int buttonId) {
    if (botoes[buttonId].initialized) {
        if (botoes[buttonId].winp) {
            if (botoes[buttonId].visible) {
                int aux = window_inform_actualButton(botoes[buttonId].windowId);
                if (aux < 0) return BUTTON_FAILURE;
                do {
                    if (botoes[aux].selected == true)
                        button_unselect(aux);
                    aux = button_next(aux);
                } while (aux != window_inform_actualButton(botoes[buttonId].windowId));
                botoes[buttonId].selected = true;
                window_set_actualButton_selected(botoes[buttonId].windowId, buttonId);
                return BUTTON_SUCCESS;
            } else return BUTTON_SUCCESS;
        } else {
            __E("Nenhuma tela associada ao botao.\n");
            return BUTTON_FAILURE;
        }
    } else {
        __E("Botao nao foi criado.\n");

        return BUTTON_FAILURE;
    }
}

int button_setVisible(int buttonId, unsigned char visibility) {
    if (botoes[buttonId].initialized) {
        if (botoes[buttonId].winp) {
            if (visibility == true || visibility == false) {
                botoes[buttonId].visible = visibility;
                return BUTTON_SUCCESS;
            } else {
                __E("Opcao invalida.\n");
                return BUTTON_FAILURE;
            }
        } else {
            __E("Nenhuma tela associada ao botao.\n");
            return BUTTON_FAILURE;
        }
    } else {
        __E("Botao nao foi criado.\n");

        return BUTTON_FAILURE;
    }
}

int button_setText(int buttonId, unsigned char *text) {
    if (botoes[buttonId].initialized) {
        if (strlen(text) > MAX_TEXT_BUTTON) {
            __E("O texto e maior que MAX_TEXT_BUTTON.\n");
            return BUTTON_FAILURE;
        } else {
            strcpy(botoes[buttonId].text, text);
            return BUTTON_SUCCESS;
        }
    } else {
        __E("Botao nao foi criado.\n");

        return BUTTON_FAILURE;
    }
}

int button_setBorder(int buttonId, unsigned int border) {
    if (botoes[buttonId].initialized) {
        if (botoes[buttonId].border == border) {
            return BUTTON_SUCCESS;
        }
        botoes[buttonId].border = border;
        return BUTTON_SUCCESS;
    } else {
        __E("Botao nao foi criado.\n");

        return BUTTON_FAILURE;
    }
}

int button_addToWindow(int buttonId, int buttonId_next, int windowId, window *winp) {
    if (botoes[buttonId_next].winp == NULL) {
        botoes[buttonId_next].next = botoes[buttonId].next;
        botoes[buttonId].next = &botoes[buttonId_next];
        botoes[buttonId_next].previous = &botoes[buttonId];
        botoes[buttonId_next].next->previous = &botoes[buttonId_next];
        botoes[buttonId_next].winp = winp;
        botoes[buttonId_next].windowId = windowId;
        return BUTTON_SUCCESS;
    } else {
        __E("Ja existe uma tela associada ao botao.\n");

        return BUTTON_FAILURE;
    }
}

signed int button_delFromWindow(signed int buttonId) {
    if (!botoes[buttonId].initialized) {
        __E("Botao nao criado.\n");
        return BUTTON_FAILURE;
    }

    if (botoes[buttonId].winp == NULL) {
        return BUTTON_SUCCESS;
    }

    if (botoes[buttonId].next == &botoes[buttonId]) {
        botoes[buttonId].winp->firstButton = -1;
        botoes[buttonId].winp->actualButton = -1;
    } else {
        if (botoes[buttonId].winp->actualButton == buttonId) {
            botoes[buttonId].winp->actualButton = botoes[botoes[buttonId].winp->actualButton].previous->id;
        } else if (botoes[buttonId].winp->firstButton == buttonId) {
            botoes[buttonId].winp->firstButton = botoes[botoes[buttonId].winp->firstButton].next->id;
        }

        botoes[buttonId].previous->next = botoes[buttonId].next;
        botoes[buttonId].next->previous = botoes[buttonId].previous;
    }

    if (botoes[buttonId].winp->actualButton_selected == botoes[buttonId].id) {
        botoes[buttonId].winp->actualButton_selected = -1;
    }

    botoes[buttonId].previous = &botoes[buttonId];
    botoes[buttonId].next = &botoes[buttonId];
    botoes[buttonId].winp = NULL;
    botoes[buttonId].windowId = -1;

    window_setComponentsRedraw(botoes[buttonId].windowId);

    return BUTTON_SUCCESS;
}

int button_previous(int buttonId) {
    if (botoes[buttonId].initialized) {
        return botoes[buttonId].previous->id;
    } else {
        __E("Botao nao foi criado.\n");

        return BUTTON_FAILURE;
    }
}

int button_next(int buttonId) {
    if (botoes[buttonId].initialized) {
        return botoes[buttonId].next->id;
    } else {
        __E("Botao nao foi criado.\n");

        return BUTTON_FAILURE;
    }
}

int button_setColor(int buttonId, unsigned int r, unsigned int g, unsigned int b) {
    if (botoes[buttonId].initialized) {
        botoes[buttonId].bg_r = r;
        botoes[buttonId].bg_g = g;
        botoes[buttonId].bg_b = b;
        return BUTTON_SUCCESS;
    } else {
        __E("Botao nao foi criado.\n");

        return BUTTON_FAILURE;
    }
}

int button_setFontColor(int buttonId, unsigned int r, unsigned int g, unsigned int b) {
    if (botoes[buttonId].initialized) {
        botoes[buttonId].font_r = r;
        botoes[buttonId].font_g = g;
        botoes[buttonId].font_b = b;
        return BUTTON_SUCCESS;
    } else {
        __E("Botao nao foi criado.\n");

        return BUTTON_FAILURE;
    }
}

signed int button_getX(signed int buttonId) {
    if (botoes[buttonId].initialized) {
        return botoes[buttonId].x;
    } else {
        __E("Botão não foi criado.\n");
        return BUTTON_FAILURE;
    }
}

signed int button_getY(signed int buttonId) {
    if (botoes[buttonId].initialized) {
        return botoes[buttonId].y;
    } else {
        __E("Botão não foi criado.\n");
        return BUTTON_FAILURE;
    }
}

signed int button_getWidth(signed int buttonId) {
    if (botoes[buttonId].initialized) {
        return botoes[buttonId].w;
    } else {
        __E("Botão não foi criado.\n");
        return BUTTON_FAILURE;
    }
}

signed int button_getHeight(signed int buttonId) {
    if (botoes[buttonId].initialized) {
        return botoes[buttonId].h;
    } else {
        __E("Botão não foi criado.\n");
        return BUTTON_FAILURE;
    }
}
int button_isSelected(int buttonId) {
    if (botoes[buttonId].initialized) return botoes[buttonId].selected;
    else {
        __E("Botao nao foi criado.\n");

        return BUTTON_FAILURE;
    }
}

int button_isBlocked(int buttonId) {
    if (botoes[buttonId].initialized) return botoes[buttonId].blocked;
    else {
        __E("Botao nao foi criado.\n");

        return BUTTON_FAILURE;
    }
}

int button_isVisible(int buttonId) {
    if (botoes[buttonId].initialized) return botoes[buttonId].visible;
    else {
        __E("Botao nao foi criado.\n");
        return BUTTON_FAILURE;
    }
}

void button_setRedraw(signed int buttonId) {
    botoes[buttonId].redraw = 1;
}
